{
  "nbformat_minor": 0,
  "cells": [
    {
      "source": [
        "#### Copyright 2017 Google LLC."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "JndnmDMp66FL"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "hMqWDc_m6rUC",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        },
        "cellView": "both"
      }
    },
    {
      "source": [
        "# Creating and Manipulating Tensors"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "P0bQXjp499sl"
      }
    },
    {
      "source": [
        "**Learning Objectives:**\n",
        "  * Initialize and assign TensorFlow `Variable`s\n",
        "  * Create and manipulate tensors\n",
        "  * Refresh your memory about addition and multiplication in linear algebra (consult an introduction to matrix [addition](https://en.wikipedia.org/wiki/Matrix_addition) and [multiplication](https://en.wikipedia.org/wiki/Matrix_multiplication) if these topics are new to you)\n",
        "  * Familiarize yourself with basic TensorFlow math and array operations"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "I3BCiWJiCGsv"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "from __future__ import print_function\n\n",
        "import tensorflow as tf\n",
        "try:\n",
        "  tf.contrib.eager.enable_eager_execution()\n",
        "  print(\"TF imported with eager execution!\")\n",
        "except ValueError:\n",
        "  print(\"TF already imported with eager execution!\")"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "85evKRsOIC5a",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "## Vector Addition\n",
        "\n",
        "You can perform many typical mathematical operations on tensors ([TF API](https://www.tensorflow.org/api_guides/python/math_ops)). The code below creates the following vectors (1-D tensors), all having exactly six elements:\n",
        "\n",
        "*  A `primes` vector containing prime numbers.\n",
        "*  A `ones` vector containing all `1` values.\n",
        "* A vector created by performing element-wise addition over the first two vectors.\n",
        "* A vector created by doubling the elements in the `primes` vector."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "PT1sorfH-DdQ"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)\n",
        "print(\"primes:\", primes\n)",
        "\n",
        "ones = tf.ones([6], dtype=tf.int32)\n",
        "print(\"ones:\", ones)\n",
        "\n",
        "just_beyond_primes = tf.add(primes, ones)\n",
        "print(\"just_beyond_primes:\", just_beyond_primes)\n",
        "\n",
        "twos = tf.constant([2, 2, 2, 2, 2, 2], dtype=tf.int32)\n",
        "primes_doubled = primes * twos\n",
        "print(\"primes_doubled:\", primes_doubled)"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "ng37e6ur-GZo",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "Printing a tensor returns not only its value, but also its shape (discussed in the next section) and the type of value stored in the tensor.  Calling the `numpy` method of a tensor returns the value of the tensor as a numpy array:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "whbEUNguEAt2"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "some_matrix = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.int32)\n",
        "print(some_matrix)\n",
        "print(\"\\nvalue of some_matrix is:\\n\", some_matrix.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "Dz4i5c88GRwJ",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Tensor Shapes\n",
        "\n",
        "Shapes are used to characterize the size and number of dimensions of a tensor. The shape of a tensor is expressed as `list`, with the `i`th element representing the size along dimension `i`. The length of the list then indicates the rank of the tensor (i.e., the number of dimensions).\n",
        "\n",
        "For more information, see the [TensorFlow documentation](https://www.tensorflow.org/programmers_guide/tensors#shape).\n",
        "\n",
        "A few basic examples:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fVvaXzzMGZid"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# A scalar (0-D tensor).\n",
        "scalar = tf.zeros([])\n",
        "\n",
        "# A vector with 3 elements.\n",
        "vector = tf.zeros([3])\n",
        "\n",
        "# A matrix with 2 rows and 3 columns.\n",
        "matrix = tf.zeros([2, 3])\n",
        "\n",
        "print('scalar has shape', scalar.get_shape(), 'and value:\\n', scalar.numpy())\n",
        "print('vector has shape', vector.get_shape(), 'and value:\\n', vector.numpy())\n",
        "print('matrix has shape', matrix.get_shape(), 'and value:\\n', matrix.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "PWzvJnIAH_cF",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Broadcasting\n",
        "\n",
        "In mathematics, you can only perform element-wise operations (e.g. *add* and *equals*) on tensors of the same shape. In TensorFlow, however, you may perform operations on tensors that would traditionally have been incompatible. TensorFlow supports **broadcasting** (a concept borrowed from numpy), where the smaller array in an element-wise operation is enlarged to have the same shape as the larger array. For example, via broadcasting:\n",
        "\n",
        "* If an operand requires a size `[6]` tensor, a size `[1]` or a size `[]` tensor can serve as an operand.\n",
        "* If an operation requires a size `[4, 6]` tensor, any of the following sizes can serve as an operand:\n",
        "  * `[1, 6]`\n",
        "  * `[6]`\n",
        "  * `[]`\n",
        "* If an operation requires a size `[3, 5, 6]` tensor, any of the following sizes can serve as an operand:\n",
        "\n",
        "  * `[1, 5, 6]`\n",
        "  * `[3, 1, 6]`\n",
        "  * `[3, 5, 1]`\n",
        "  * `[1, 1, 1]`\n",
        "  * `[5, 6]`\n",
        "  * `[1, 6]`\n",
        "  * `[6]`\n",
        "  * `[1]`\n",
        "  * `[]`\n",
        "\n",
        "**NOTE:** When a tensor is broadcast, its entries are conceptually **copied**. (They are not actually copied for performance reasons. Broadcasting was invented as a performance optimization.)\n",
        "\n",
        "The full broadcasting ruleset is well described in the easy-to-read [numpy broadcasting documentation](http://docs.scipy.org/doc/numpy-1.10.1/user/basics.broadcasting.html).\n",
        "\n",
        "The following code performs the same tensor arithmetic as before, but instead uses scalar values (instead of vectors containing all `1`s or all `2`s) and broadcasting."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "musamrLavR5S"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)\n",
        "print(\"primes:\", primes)\n",
        "\n",
        "one = tf.constant(1, dtype=tf.int32)\n",
        "print(\"one:\", one)\n",
        "\n",
        "just_beyond_primes = tf.add(primes, one)\n",
        "print(\"just_beyond_primes:\", just_beyond_primes)\n",
        "\n",
        "two = tf.constant(2, dtype=tf.int32)\n",
        "primes_doubled = primes * two\n",
        "print(\"primes_doubled:\", primes_doubled)"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "7lys_BeLy2SD",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Exercise #1: Arithmetic over vectors.\n",
        "\n",
        "Perform vector arithmetic to create a \"just_under_primes_squared\" vector, where the `i`th element is equal to the `i`th element in `primes` squared, minus 1.  For example, the second element would be equal to `3 * 3 - 1 = 8`.\n",
        "\n",
        "Make use of either the `tf.multiply` or `tf.pow` ops to square the value of each element in the `primes` vector."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "FPBzBzRROxwe"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Write your code for Task 1 here."
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "pWK2rAttQlD6",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Solution\n",
        "\n",
        "Click below for a solution."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "7d1kfAx4QL17"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Task: Square each element in the primes vector, then subtract 1.\n",
        "\n",
        "def solution(primes):\n",
        "  primes_squared = tf.multiply(primes, primes)\n",
        "  neg_one = tf.constant(-1, dtype=tf.int32)\n",
        "  just_under_primes_squared = tf.add(primes_squared, neg_one)\n",
        "  return just_under_primes_squared\n",
        "\n",
        "def alternative_solution(primes):\n",
        "  primes_squared = tf.pow(primes, 2)\n",
        "  one = tf.constant(1, dtype=tf.int32)\n",
        "  just_under_primes_squared = tf.subtract(primes_squared, one)\n",
        "  return just_under_primes_squared\n",
        "\n",
        "primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)\n",
        "just_under_primes_squared = solution(primes)\n",
        "print(\"just_under_primes_squared:\", just_under_primes_squared)"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "QUgHSI9BOUx7",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "## Matrix Multiplication\n",
        "\n",
        "In linear algebra, when multiplying two matrices, the number of *columns* of the first matrix must\n",
        "equal the number of *rows* in the second matrix.\n",
        "\n",
        "- It is **_valid_** to multiply a `3x4` matrix by a `4x2` matrix. This will result in a `3x2` matrix.\n",
        "- It is **_invalid_** to multiply a `4x2` matrix by a `3x4` matrix."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "it0P-AV0-Jb4"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# A 3x4 matrix (2-d tensor).\n",
        "x = tf.constant([[5, 2, 4, 3], [5, 1, 6, -2], [-1, 3, -1, -2]],\n",
        "                dtype=tf.int32)\n",
        "\n",
        "# A 4x2 matrix (2-d tensor).\n",
        "y = tf.constant([[2, 2], [3, 5], [4, 5], [1, 6]], dtype=tf.int32)\n",
        "\n",
        "# Multiply `x` by `y`; result is 3x2 matrix.\n",
        "matrix_multiply_result = tf.matmul(x, y)\n",
        "\n",
        "print(matrix_multiply_result)"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "OVR8QPif-MeS",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "## Tensor Reshaping\n",
        "\n",
        "With tensor addition and matrix multiplication each imposing constraints\n",
        "on operands, TensorFlow programmers must frequently reshape tensors. \n",
        "\n",
        "You can use the `tf.reshape` method to reshape a tensor. \n",
        "For example, you can reshape a 8x2 tensor into a 2x8 tensor or a 4x4 tensor:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fziRnmuy-O9x"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Create an 8x2 matrix (2-D tensor).\n",
        "matrix = tf.constant(\n",
        "    [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],\n",
        "    dtype=tf.int32)\n",
        "\n",
        "reshaped_2x8_matrix = tf.reshape(matrix, [2, 8])\n",
        "reshaped_4x4_matrix = tf.reshape(matrix, [4, 4])\n",
        "\n",
        "print(\"Original matrix (8x2):\")\n",
        "print(matrix.numpy())\n",
        "print(\"Reshaped matrix (2x8):\")\n",
        "print(reshaped_2x8_matrix.numpy())\n",
        "print(\"Reshaped matrix (4x4):\")\n",
        "print(reshaped_4x4_matrix.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "L05ob6a_G77m",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "\n",
        "You can also use `tf.reshape` to change the number of dimensions (the \"rank\") of the tensor.\n",
        "For example, you could reshape that 8x2 tensor into a 3-D 2x2x4 tensor or a 1-D 16-element tensor."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "b6cFa92YGyU5"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Create an 8x2 matrix (2-D tensor).\n",
        "matrix = tf.constant(\n",
        "    [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],\n",
        "    dtype=tf.int32)\n",
        "\n",
        "reshaped_2x2x4_tensor = tf.reshape(matrix, [2, 2, 4])\n",
        "one_dimensional_vector = tf.reshape(matrix, [16])\n",
        "\n",
        "print(\"Original matrix (8x2):\")\n",
        "print(matrix.numpy())\n",
        "print(\"Reshaped 3-D tensor (2x2x4):\")\n",
        "print(reshaped_2x2x4_tensor.numpy())\n",
        "print(\"1-D vector:\")\n",
        "print(one_dimensional_vector.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "3MpcwWj9-Sqp",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Exercise #2: Reshape two tensors in order to multiply them.\n",
        "\n",
        "The following two vectors are incompatible for matrix multiplication:\n",
        "\n",
        "  *  `a = tf.constant([5, 3, 2, 7, 1, 4])`\n",
        "  *  `b = tf.constant([4, 6, 3])`\n",
        "\n",
        "Reshape these vectors into compatible operands for matrix multiplication.\n",
        "Then, invoke a matrix multiplication operation on the reshaped tensors."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "CrpowaWo-VLq"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Write your code for Task 2 here."
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "p6idvaeK-Zxq",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Solution\n",
        "\n",
        "Click below for a solution."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "EYzU56M4MG_x"
      }
    },
    {
      "source": [
        "Remember, when multiplying two matrices, the number of *columns* of the first matrix must equal the number of *rows* in the second matrix.\n",
        "\n",
        "One possible solution is to reshape `a` into a 2x3 matrix and reshape `b` into a a 3x1 matrix, resulting in a 2x1 matrix after multiplication:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "F9HDdiugJKpH"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Task: Reshape two tensors in order to multiply them\n",
        "\n",
        "a = tf.constant([5, 3, 2, 7, 1, 4])\n",
        "b = tf.constant([4, 6, 3])\n",
        "\n",
        "reshaped_a = tf.reshape(a, [2, 3])\n",
        "reshaped_b = tf.reshape(b, [3, 1])\n",
        "c = tf.matmul(reshaped_a, reshaped_b)\n",
        "\n",
        "print(\"reshaped_a (2x3):\")\n",
        "print(reshaped_a.numpy())\n",
        "print(\"reshaped_b (3x1):\")\n",
        "print(reshaped_b.numpy())\n",
        "print(\"reshaped_a x reshaped_b (2x1):\")\n",
        "print(c.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "8Sef4d0SMMtk",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "An alternative solution would be to reshape `a` into a 6x1 matrix and `b` into a 1x3 matrix, resulting in a 6x3 matrix after multiplication."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "uDZSacTxJ0XG"
      }
    },
    {
      "source": [
        "## Variables, Initialization and Assignment\n",
        "\n",
        "So far, all the operations we performed were on static values (`tf.constant`); calling `numpy()` always returned the same result. TensorFlow allows you to define `Variable` objects, whose values can be changed.\n",
        "\n",
        "When creating a variable, you can set an initial value explicitly, or you can use an initializer (like a distribution):"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "x1JYo7iE2oKk"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Create a scalar variable with the initial value 3.\n",
        "v = tf.contrib.eager.Variable([3])\n",
        "\n",
        "# Create a vector variable of shape [1, 4], with random initial values,\n",
        "# sampled from a normal distribution with mean 1 and standard deviation 0.35.\n",
        "w = tf.contrib.eager.Variable(tf.random_normal([1, 4], mean=1.0, stddev=0.35))\n",
        "\n",
        "print(\"v:\", v.numpy())\n",
        "print(\"w:\", w.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "6opLnjfD3PdL",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "To change the value of a variable, use the `assign` op:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "yrZ31hPw66uy"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "v = tf.contrib.eager.Variable([3])\n",
        "print(v.numpy())\n",
        "\n",
        "tf.assign(v, [7])\n",
        "print(v.numpy())\n",
        "\n",
        "v.assign([5])\n",
        "print(v.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "zD0D1DCR7NBX",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "When assigning a new value to a variable, its shape must be equal to its previous shape:"
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "HQvQCZvuLKfY"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "v = tf.contrib.eager.Variable([[1, 2, 3], [4, 5, 6]])\n",
        "print(v.numpy())\n",
        "\n",
        "try:\n",
        "  print(\"Assigning [7, 8, 9] to v\")\n",
        "  v.assign([7, 8, 9])\n",
        "except ValueError as e:\n",
        "  print(\"Exception:\", e)"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "AoSJFAlkLHTX",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "There are many more topics about variables that we didn't cover here, such as loading and storing. To learn more, see the [TensorFlow docs](https://www.tensorflow.org/programmers_guide/variables)."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "tB78Zq4h78Zr"
      }
    },
    {
      "source": [
        "### Exercise #3: Simulate 10 rolls of two dice.\n",
        "\n",
        "Create a dice simulation, which generates a `10x3` 2-D tensor in which:\n",
        "\n",
        "  * Columns `1` and `2` each hold one throw of one six-sided die (with values 1\u20136).\n",
        "  * Column `3` holds the sum of Columns `1` and `2` on the same row.\n",
        "\n",
        "For example, the first row might have the following values:\n",
        "\n",
        "  * Column `1` holds `4`\n",
        "  * Column `2` holds `3`\n",
        "  * Column `3` holds `7`\n",
        "\n",
        "You'll need to explore the [TensorFlow API reference](https://www.tensorflow.org/api_docs/python/tf) to solve this task."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "iFIOcnfz_Oqw"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Write your code for Task 3 here."
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "ocwT0iXH-nhT",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    },
    {
      "source": [
        "### Solution\n",
        "\n",
        "Click below for a solution."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Kt7aojXkR_qS"
      }
    },
    {
      "source": [
        "We're going to place dice throws inside two separate 10x1 matrices, `die1` and `die2`.  The summation of the dice rolls will be stored in `dice_sum`, then the resulting 10x3 matrix will be created by *concatenating* the three 10x1 matrices together into a single matrix.\n",
        "\n",
        "Alternatively, we could have placed dice throws inside a single 10x2 matrix, but adding different columns of the same matrix would be more complicated. We also could have placed dice throws inside two 1-D tensors (vectors), but doing so would require transposing the result."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "6kRkwXE1MHVS"
      }
    },
    {
      "execution_count": 0,
      "cell_type": "code",
      "source": [
        "# Task: Simulate 10 throws of two dice. Store the results in a 10x3 matrix.\n",
        "\n",
        "die1 = tf.contrib.eager.Variable(\n",
        "    tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))\n",
        "die2 = tf.contrib.eager.Variable(\n",
        "    tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))\n",
        "\n",
        "dice_sum = tf.add(die1, die2)\n",
        "resulting_matrix = tf.concat(values=[die1, die2, dice_sum], axis=1)\n",
        "\n",
        "print(resulting_matrix.numpy())"
      ],
      "outputs": [],
      "metadata": {
        "colab_type": "code",
        "id": "6UUluecQSCvr",
        "colab": {
          "autoexec": {
            "wait_interval": 0,
            "startup": false
          }
        }
      }
    }
  ],
  "nbformat": 4,
  "metadata": {
    "colab": {
      "default_view": {},
      "name": "creating_and_manipulating_tensors.ipynb",
      "views": {},
      "provenance": [],
      "collapsed_sections": [
        "JndnmDMp66FL",
        "7d1kfAx4QL17",
        "EYzU56M4MG_x",
        "Kt7aojXkR_qS"
      ],
      "version": "0.3.2"
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  }
}
